<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>my_hls</title>
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
    <script src="./js/video.js"></script>
    <script src="./js/vendor/modernizr-2.6.2.min.js"></script>
    <script src="./js/mux.js"></script>
    <script>
        function myhls(opt, video) {
            this.opt = {
                url: '', //request address
                host: '',//'//120.55.85.1:8001',
                path: '',
                duration: 10,  //ts file's duration
                interval: 10,  //the spacing between two request
            }
            this.requestArr = [];
            this.requestedArr = [];
            this.m3u8Arry = [];
            this.queue = [];
            this.video = video;
            this.media = {
                mimeCodec: `video/mp4; codecs="avc1.64001f"`,
                mediaSource: null
            };
            this.m3u8Interval = null;
            this.tsInterval = null;
            this.bufferInterval = null;
            this.currentTsIndex = 0;
            this.transmuxer = void 0;
            this.videoTime = 0;
            var _this = this,
                vjsParsed,
                diffParsed,
                vjsBytes;
            this.isMobile = {
                Android: function () {
                    return navigator.userAgent.match(/Android/i) ? true : false;
                },
                BlackBerry: function () {
                    return navigator.userAgent.match(/BlackBerry/i) ? true : false;
                },
                iOS: function () {
                    return navigator.userAgent.match(/iPhone|iPad|iPod/i) ? true : false;
                },
                OS: function () {
                    return navigator.userAgent.match(/Mac/i) ? true : false;
                },
                Windows: function () {
                    return navigator.userAgent.match(/IEMobile/i) ? true : false;
                },
                any: function () {
                    return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
                }
            }

            // var assetURL = '/proxy_ip120.55.85.1:5112/33T1HZ/KX9001201706.m3u8';
            if (opt) {
                if (typeof opt == 'object') this.opt = Object.assign(this.opt, opt);
                else if (typeof opt == 'string') this.opt.url = opt;
                else ERROR('unsurpported options');
            }
            if ('MediaSource' in window) {
            } else {
                console.error('Unsupported MIME type or codec: ', mimeCodec);
            }
            this.distroy = function () {
                _this.video.src = '';
                _this.requestArr = [];
                _this.requestedArr = [];
                _this.m3u8Arry = [];
                _this.queue = [];
                _this.video = video;
                _this.media = {
                    mimeCodec: `video/mp4; codecs="avc1.64001f"`,
                    mediaSource: null
                };
                _this.currentTsIndex = 0;
                _this.transmuxer = void 0;
                _this.videoTime = 0;
                clearInterval(_this.m3u8Interval);
                clearInterval(_this.tsInterval);
                clearInterval(_this.bufferInterval);
                _this.bufferInterval = null;
                _this.m3u8Interval = null;
                _this.tsInterval = null;
            }
            this.init = function () {
                if (_this.isMobile.iOS() || _this.isMobile.OS()) {
                    video.src = _this.opt.host + _this.opt.url;
                } else {
                    if (MediaSource.isTypeSupported(_this.media.mimeCodec)) {
                        requestMU(_this.opt.host + _this.opt.url)
                    }
                }

            }
            function bufferRemoveInterval() {
                _this.bufferInterval = setInterval(function () {
                    if (!_this.video.paused) {
                        var totalTime = _this.media.mediaSource.duration;
                        var currentTime = _this.video.currentTime;
                        !_this.sourceBuffer.updating && currentTime > 20 && _this.sourceBuffer.remove(0, currentTime - 4);
                        (_this.video.currentTime >= _this.video.duration - 0.9) && _this.video.pause();
                        if (_this.video.currentTime <= _this.video.duration - 3 && this.videoTime == _this.video.currentTime) {
                            _this.video.currentTime++;
                            this.videoTime++;
                        } else {
                            this.videoTime = _this.video.currentTime
                        }
                        // _this.video.duration -= (totalTime - currentTime);
                        // _this.video.currentTime = 0;
                    } else {
                        _this.video.play()
                    }
                }, 4000)
            }
            logevent = function (event) {
                console.log(event);
            };
            function requestTs(url) {
                return new Promise(function (resolve, reject) {
                    if (window.fetch) {
                        // var thisurl = url.replace(_this.opt.host, '')
                        // if (_this.requestedArr.indexOf(thisurl) != -1) return false;
                        var ft = fetch(url)
                            .then(buf => {
                                // _this.requestedArr.push(thisurl);
                                // if (_this.requestedArr.length > 20) {
                                //     var dv = _this.requestedArr.length - 20;
                                //     _this.requestArr.splice(0, dv);
                                //     _this.requestedArr.splice(0, dv);
                                //     _this.currentTsIndex -= dv;
                                // }
                                return buf.arrayBuffer();
                            })
                            .then(buf => {
                                var u8 = new Uint8Array(buf);
                                return u8
                            })
                            .then(buf => {
                                return new Blob([buf], { type: 'video/mp4' })
                            })
                            .then(blob => {
                                var reader = new FileReader();
                                reader.onload = e => {
                                    if (e.target.result) resolve(new Uint8Array(e.target.result))
                                    else reject(new Error('buf is empty'))
                                }
                                reader.readAsArrayBuffer(blob)
                            })
                    }
                })
            }
            function requestMU(url, cb) {
                if (window.fetch) {
                    var ft = fetch(url).then(data => {
                        return data.text();
                    }).then(data => {
                        var $data = data.split('\n');
                        const appendTsBuffer = (tsURL) => {
                            return new Promise(function (resolve, reject) {
                                if (tsURL) {
                                    requestTs(_this.opt.host + tsURL).then(function (buf) {
                                        flushTs(buf)
                                        // _this.currentTsIndex++
                                        resolve(_this.currentTsIndex)
                                    });
                                };
                            })
                        }
                        for (var i of $data) {
                            i = i.replace(/[\r\n]/gi, '');
                            if (/^http/.test(i) && _this.requestedArr.indexOf(i) == -1 && _this.m3u8Arry.indexOf(i) == -1) {
                                // _this.requestArr.push(i)
                                _this.m3u8Arry.push(i);
                                if (_this.requestedArr.length >= 10) _this.requestedArr.splice(0, 10)
                            }
                            if (/EXTINF/gi.test(i)) {
                                _this.opt.interval = i.match(/\d{1,}/g)[0] - 0;
                                _this.opt.duration = _this.opt.interval / 4;
                            }
                        }
                        // !!_this.m3u8Arry.length && (console.log(_this.m3u8Arry), console.log(_this.requestArr))
                        // var i = 0;
                        // _this.opt.interval = _this.opt.duration * _this.m3u8Arry.length;
                        // const appendFun = async function (i) {
                        //     // debugger
                        //     while (i < _this.m3u8Arry.length) {
                        //         await appendTsBuffer(_this.m3u8Arry[i]);
                        //         i++
                        //     }
                        // }
                        !_this.tsInterval ? _this.tsInterval = setInterval(function () {
                            if (_this.m3u8Arry.length > 0) {
                                let m3u8Url = _this.m3u8Arry.shift();
                                console.log('_this.m3u8Arry:', _this.m3u8Arry)
                                console.log('m3u8Url:', m3u8Url)
                                _this.requestedArr.push(m3u8Url)
                                appendTsBuffer(m3u8Url)
                            }
                        }, 1000) : '';
                        // appendFun(i);
                        !_this.m3u8Interval ? _this.m3u8Interval = setInterval(function () {
                            requestMU(_this.opt.host + _this.opt.url)
                        }, _this.opt.duration * 1000) : '';
                    })
                }
            }
            function prepareSourceBuffer(callback) {
                var mediaSource = _this.media.mediaSource = new MediaSource();
                _this.video.src = URL.createObjectURL(mediaSource);
                mediaSource.addEventListener('sourceopen', function () {
                    mediaSource.duration = 0;
                    buffer = mediaSource.addSourceBuffer(_this.media.mimeCodec);
                    buffer.addEventListener('updateend', function () {
                        if (_this.queue.length > 0) {
                            let bytes = _this.queue.shift()
                            _this.sourceBuffer.appendBuffer(bytes)
                        }
                    })
                    buffer.addEventListener('error', function (e) {
                        console.log(event);
                        _this.distroy();
                        _this.init()
                    });
                    _this.sourceBuffer = buffer;
                    return callback();
                });
            }
            function flushTs(buf) {
                var segment = buf,
                    remuxedSegments = [],
                    remuxedInitSegment = null,
                    remuxedBytesLength = 0,
                    createInitSegment = false,
                    bytes,
                    i, j;

                if (!_this.transmuxer) {
                    createInitSegment = true;
                    _this.transmuxer = new muxjs.mp4.Transmuxer({ remux: false });

                    _this.transmuxer.on('data', function (event) {
                        remuxedSegments.push(event);
                        remuxedBytesLength += event.data.byteLength;
                        remuxedInitSegment = event.initSegment;
                    });

                    _this.transmuxer.on('done', function () {
                        var offset = 0;
                        if (createInitSegment) {
                            bytes = new Uint8Array(remuxedInitSegment.byteLength + remuxedBytesLength)
                            bytes.set(remuxedInitSegment, offset);
                            offset += remuxedInitSegment.byteLength;
                            createInitSegment = false;
                        } else {
                            bytes = new Uint8Array(remuxedBytesLength);
                        }

                        for (j = 0, i = offset; j < remuxedSegments.length; j++) {
                            bytes.set(remuxedSegments[j].data, i);
                            i += remuxedSegments[j].byteLength;
                        }
                        muxedData = bytes;
                        remuxedSegments = [];
                        remuxedBytesLength = 0;

                        vjsBytes = bytes;
                        vjsParsed = muxjs.mp4.tools.inspect(bytes);
                        // diffParsed();
                        try {
                            if (!_this.media.mediaSource) {
                                prepareSourceBuffer(function () {
                                    _this.sourceBuffer.appendBuffer(bytes);
                                    _this.video.play();
                                    bufferRemoveInterval()
                                });
                            } else {
                                // _this.sourceBuffer.updating == false && _this.sourceBuffer.remove(0, _this.video.currentTime)
                                if (!_this.sourceBuffer.updating)
                                    _this.sourceBuffer.appendBuffer(bytes);
                                else
                                    _this.queue.push(bytes)
                                // _this.video.paused && _this.video.play();
                            }
                        } catch (e) {
                            _this.distroy();
                            _this.init()
                        }
                    });
                }

                _this.transmuxer.push(segment);
                _this.transmuxer.flush();
            }
            function ERROR(warning) {
                throw new Error(warning);
            }
            _this.init()
        }
    </script>
</head>

<body>
    <video id="video" controls></video>
    <script>
        window.onload = function () {
            window.hls = new myhls('//120.55.85.1:5112/33T1HZ/KX9001201706.m3u8', document.getElementById('video')) ////proxy_ip120.55.85.1:5112/33T1HZ/KX9001201706.m3u8
        }
    </script>
</body>

</html>